package com.example.filter;

import com.auth0.jwt.interfaces.DecodedJWT;
import com.example.utils.JwtUtil;
import jakarta.annotation.Resource;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import java.io.IOException;

/**
 * JWT授权过滤器，每次请求时校验JWT令牌并设置认证信息
 * 继承OncePerRequestFilter，保证每次请求只执行一次过滤逻辑
 *
 * @auth shanyue
 * @date 2025年06月19日11:45
 */
@Component
public class JwtAuthorizeFilter extends OncePerRequestFilter {

    @Resource
    JwtUtil util;

    /**
     * 过滤器逻辑，每次请求会被此方法拦截处理
     *
     * @param request     当前请求
     * @param response    当前响应
     * @param filterChain 过滤器链，传递请求
     * @throws ServletException 过滤器异常
     * @throws IOException      IO异常
     */
    @Override
    protected void doFilterInternal(HttpServletRequest request,
                                    HttpServletResponse response,
                                    FilterChain filterChain) throws ServletException, IOException {

        //获取请求头中的Authorization字段(JWT令牌)
        String authorization = request.getHeader("Authorization");

        //解析JWT令牌(校验签名和过期时间)，解析失败返回null
        DecodedJWT jwt = util.resolveJwt(authorization);
        if (jwt != null) {
            //从JWT中还原出UserDetails对象
            UserDetails user = util.toUser(jwt);
            //创建认证对象，参数：用户、凭证、权限列表
            UsernamePasswordAuthenticationToken authenticationToken =
                    new UsernamePasswordAuthenticationToken(user, null, user.getAuthorities());
            //设置请求相关的认证详情
            authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
            //将认证对象存入SpringSecurity上下文，表示当前请求已登录
            SecurityContextHolder.getContext().setAuthentication(authenticationToken);
            //将用户ID添加到请求属性中，后续可以使用
            request.setAttribute("id", util.toId(jwt));
        }
        //将请求继续传递给下一个过滤器或目标处理器
        filterChain.doFilter(request, response);
    }
}
